package base

import (
	"bytes"
	"encoding/xml"
	"errors"
	"fmt"
	"io/ioutil"
	glog "log"
	"net/http"
	"net/url"
	"shqsoft.cn/pasnj/ntlmv1"
	"strings"
)

//ReportConfig 报表定义
type ReportConfig struct {
	XMLName     xml.Name     `xml:"Reports"`
	ReportItems []ReportItem `xml:"Report"`
}

//GetReportItem 获取报表项目
func (r *ReportConfig) GetReportItem(permID int) *ReportItem {
	for _, item := range r.ReportItems {
		if item.PerminissionID == permID {
			return &item
		}
	}
	return nil
}

//ReportItem 报表项目
type ReportItem struct {
	PerminissionID int               `xml:"PerminissionId,attr"`
	Name           string            `xml:"Name,attr"`
	FileName       string            `xml:"FileName,attr"`
	IsLoadInit     bool              `xml:"IsLoadInit,attr"`
	Parameters     []ReportParameter `xml:"Parameter"`
}

//ReportParameter 报表参数
type ReportParameter struct {
	Name             string `xml:"Name,attr"`
	Caption          string `xml:"Caption,attr"`
	EditType         string `xml:"EditType,attr"`
	Width            int    `xml:"Width,attr"`
	LabelSpan        int    `xml:"LabelSpan,attr"`
	WrapperSpan      int    `xml:"WrapperSpan,attr"`
	DataSourceType   string `xml:"DataSourceType,attr"`
	DataExp          string `xml:"DataExp,attr"`
	IsCanMultiSelect bool   `xml:"IsCanMultiSelect,attr"`
	InitValue        string `xml:"InitValue,attr"`
	InitLabel        string `xml:"InitLabel,attr"`
	OrderBY          string `xml:"OrderBY,attr"`
}
//SearchOption 搜索选项
func (ri *ReportItem) SearchOption(paramName string, searchValue string) (map[string]string, error) {
	var param *ReportParameter
	for _, p := range ri.Parameters {
		if p.Name == paramName {
			param = &p
			break
		}
	}
	if param == nil {
		return nil, fmt.Errorf("为报表%s提供的参数名%s不存在", ri.FileName, paramName)
	}
	if param.EditType != "auto" {
		return nil, fmt.Errorf("报表%s参数%s没有配置为自动搜索", ri.FileName, paramName)
	}
	if strings.ToUpper(param.DataSourceType) != "SQL" {
		return nil, errors.New("目前针对自动搜索只开启了SQL数据源！")
	}
	if strings.TrimSpace(param.DataExp) == "=" {
		return nil, fmt.Errorf("没有给报表%s的参数%s配置DataExp", ri.FileName, paramName)
	}
	sql := strings.Replace(param.DataExp, "?", searchValue, -1)
	rows, err := DB.Raw(sql).Order(param.OrderBY).Limit(7).Rows()
	defer rows.Close()
	if err != nil {
		return nil, err
	}
	options := make(map[string]string)
	for rows.Next() {
		var id, name string
		if err := rows.Scan(&id, &name); err != nil {
			return nil, fmt.Errorf("执行报表参数自动搜索时出错,%s", err)
		}
		options[id] = name
	}
	return options, nil
}

//SSRSReport 处理SSRS报表访问的类
type SSRSReport struct {
	client  *http.Client
	url     string
	catalog string
}

//ReportDef 报表定义
var ReportDef ReportConfig

func init() {
	var err error
	var workPath string
	if workPath, err = WorkDir(); err != nil {
		glog.Printf("获取执行路径出错！%s", err)
		return
	}
	filePath := workPath + "/config/report.xml"
	if xmlBytes, err := ioutil.ReadFile(filePath); err == nil {
		if err := xml.Unmarshal(xmlBytes, &ReportDef); err != nil {
			glog.Printf("加载Report配置文件失败！%s", err)
		}
	}
}

//NewSSRSReport 创建SSRS报表访问对象
func NewSSRSReport() *SSRSReport {
	client := &http.Client{
		Transport: &http.Transport{
			Dial: ntlm.NewHTTPDialer(Context.SSRS.UserName,
				Context.SSRS.Password,
				Context.SSRS.Domain,
				Context.SSRS.Url),
		},
	}
	return &SSRSReport{
		client:  client,
		url:     Context.SSRS.Url,
		catalog: Context.SSRS.Catalog,
	}
}

//ConnReport 连接SSRS报表服务器
func (s *SSRSReport) ConnReport(url string) (*http.Response, error) {
	return s.client.Get(url)
}

//GetURL 获取报表访问URL
func (s *SSRSReport) GetURL(reportName string, params map[string]string) (string, error) {
	var buff bytes.Buffer
	buff.WriteString("?")
	buff.WriteString("/")
	buff.WriteString(s.catalog)
	buff.WriteString("/")
	buff.WriteString(reportName)
	rPath, err := s.encode(buff.String())
	if err != nil {
		return "", err
	}
	rPath = strings.TrimRight(rPath, "=")
	buff.Reset()
	buff.WriteString("?rs:Format=HTML4.0")
	for k, v := range params {
		buff.WriteString("&")
		buff.WriteString(k)
		buff.WriteString("=")
		buff.WriteString(strings.Replace(v, "&", "%26", -1))
	}
	query := buff.String()
	query, err = s.encode(query)
	if err != nil {
		return "", err
	}
	path := s.url + "?" + rPath + "&" + query
	return path, nil
}
func (s *SSRSReport) encode(val string) (string, error) {
	var retVal string
	uri, err := url.Parse(val)
	if err != nil {
		return "", err
	}
	retVal = uri.Query().Encode()
	return retVal, nil
}
